#include "partie.h"

#include "../App/utils.h"
#include "carte.h"
#include "fonction.h"

#include <QtCore/QMap>
#include <QtCore/QPair>
#include <QtCore/QString>
#include <QtCore/QStringList>
#include <QtCore/QVector>
#include <QtGui/QGraphicsPixmapItem>

#include <QtCore/QDebug>

Partie* Partie::_instance = 0;

/*****************************************
  TODO: Réfléchir à la disposition des joueurs si 5 joueurs (3?)
*****************************************/

Partie::Partie() {
    m_jeu = new QVector<Carte*>;
    m_chien = new QVector<Carte*>;
    m_jeux = new QMap<Carte*, QString>;
}

Partie::~Partie() {
    for (int i=0; i < m_jeu->size(); i++)
        delete m_jeu->at(i);
    delete m_jeu;
    delete m_jeux;
    delete m_chien;
}

void Partie::destroy() {
    delete _instance;
    _instance = 0;
}

Partie* Partie::getInstance() {
    if (_instance == 0)
        _instance = new Partie();
    return _instance;
}

/*! \brief Initialisation de la partie.

    Création de l'ensemble des cartes du jeu.

    \param pNomJoueurs  Liste des noms des joueurs de la partie.
    \param pPouce       Booléen permettant de savoir si l'enchère Pouce est autorisée ou non.
*/
void Partie::init(QStringList pNomJoueurs, bool pPouce) {
    m_pouce = pPouce;
    m_nomsJoueurs = pNomJoueurs;

    // Création du jeu de cartes
    for (int i=0; i < 10; i++)
        m_jeu->append(new Carte(i+1, pc::Coeur, pc::None));
    m_jeu->append(new Carte(-1, pc::Coeur, pc::Valet));
    m_jeu->append(new Carte(-1, pc::Coeur, pc::Cavalier));
    m_jeu->append(new Carte(-1, pc::Coeur, pc::Dame));
    m_jeu->append(new Carte(-1, pc::Coeur, pc::Roi));

    for (int i=0; i < 10; i++)
        m_jeu->append(new Carte(i+1, pc::Carreaux, pc::None));
    m_jeu->append(new Carte(-1, pc::Carreaux, pc::Valet));
    m_jeu->append(new Carte(-1, pc::Carreaux, pc::Cavalier));
    m_jeu->append(new Carte(-1, pc::Carreaux, pc::Dame));
    m_jeu->append(new Carte(-1, pc::Carreaux, pc::Roi));

    for (int i=0; i < 10; i++)
        m_jeu->append(new Carte(i+1, pc::Pique, pc::None));
    m_jeu->append(new Carte(-1, pc::Pique, pc::Valet));
    m_jeu->append(new Carte(-1, pc::Pique, pc::Cavalier));
    m_jeu->append(new Carte(-1, pc::Pique, pc::Dame));
    m_jeu->append(new Carte(-1, pc::Pique, pc::Roi));

    for (int i=0; i < 10; i++)
        m_jeu->append(new Carte(i+1, pc::Trefle, pc::None));
    m_jeu->append(new Carte(-1, pc::Trefle, pc::Valet));
    m_jeu->append(new Carte(-1, pc::Trefle, pc::Cavalier));
    m_jeu->append(new Carte(-1, pc::Trefle, pc::Dame));
    m_jeu->append(new Carte(-1, pc::Trefle, pc::Roi));

    for (int i=0; i < 21; i++)
        m_jeu->append(new Carte(i+1, pc::Atout, pc::None));
    m_jeu->append(new Carte(-1, pc::Atout, pc::Excuse));

    melanger();

    // TODO: Déterminer les bonnes positions de départ
    m_positions.append(QPair<int,int>(500,500));
    m_positions.append(QPair<int,int>(1500,50));
    m_positions.append(QPair<int,int>(0,500));
    m_positions.append(QPair<int,int>(0,0));

    /*for (int i=0; i < m_nomsJoueurs.size(); i++) {
        m_positions.append(QPair<int,int>(0,0));
    }*/
}

/*! \brief Lancement de la partie.

    Distribution des cartes.

    (...)
*/
void Partie::launch() {
    int indexJoueur = 0;

    m_index = 0;
    while (m_index < 78)
        if (m_index == K_PALIERCHIEN_1 || m_index == K_PALIERCHIEN_2 || m_index == K_PALIERCHIEN_3) {
            ajouterChien(m_index);
        } else {
            distribuer(m_nomsJoueurs.at(indexJoueur), m_index);
            indexJoueur++;
            if (indexJoueur == 4)
                indexJoueur = 0;
        }

    /*qDebug() << "Affichage du chien: ";
    for (int i=0; i < m_chien->size(); i++)
        afficherCarte(m_chien->at(i));
    qDebug() << m_chien->size();

    qDebug() << "Affichage des jeux:";
    for (int i=0; i < m_nomsJoueurs->size(); i++) {
        qDebug() << "Joueur: " << m_nomsJoueurs->at(i);
        for ( int k=0; k < 78; k++)
            if (m_jeux->value(m_jeu->at(k)) == m_nomsJoueurs->at(i))
                afficherCarte(m_jeu->at(k));
    }*/
}

/*! \brief Cette fonction permet de mélanger le jeu. */
void Partie::melanger() {
    for (int i=0; i < 100; i++)
        inverser(m_jeu);
}

/*! \brief Fonction de distribution des cartes.

    Cette fonction permet de distribuer les cartes pour créer les jeux des différents joueurs.
    Elle émet des signaux permettant l'affichage de chaque carte distribuée.

    \param pNomJoueur   Nom du joueur auquel il faut distribuer les 3 cartes suivantes.
    \param pJeuIndex    Index de la carte actuelle dans le jeu (sabot).
*/
void Partie::distribuer(QString pNomJoueur, int pJeuIndex) {
    // TODO: calculer les bonnes indentations pour les positions
    for (int i=0; i < 3; i++) {
        m_jeux->insert(m_jeu->at(pJeuIndex+i), pNomJoueur);
        if (pNomJoueur == m_nomsJoueurs.at(0)) {
            // Set de l'offset de la pixmap (position)
            m_jeu->at(pJeuIndex+i)->getImage()->setOffset(m_positions.at(0).first, m_positions.at(0).second);
            // Modification de la position pour le prochain affichage
            m_positions[0].first += 50;
            emit afficherCarteJoueur(m_jeu->at(pJeuIndex+i)->getImage());
        } else {
            // Récupération de l'index du joueur
            int index = m_nomsJoueurs.indexOf(pNomJoueur);
            // Set de l'offset de la pixmap (position)
            m_jeu->at(pJeuIndex+i)->getImage()->setOffset(m_positions.at(index).first, m_positions.at(index).second);
            // Modification de la position pour le prochain affichage
            if (index == 3)
                m_positions[index].first += 50;
            else
                m_positions[index].second += 50;
            emit afficherCarteAutre(m_jeu->at(pJeuIndex+i)->getImage());
        }
    }
    m_index += 3;
}

/*! \brief Fonction d'ajout de cartes dans le chien.

    Cette fonction permet de constituer le chien.
    Elle émet un signal pour l'affichage des cartes dans la zone graphique.

    \param pJeuIndex    Index de la carte actuelle dans le jeu (sabot).
*/
void Partie::ajouterChien(int pJeuIndex) {
    if (m_nomsJoueurs.count() == 5) {
        for (int i=0; i < K_NBDISTCHIEN_5; i++) {
            m_chien->append(m_jeu->at(pJeuIndex+i));
            emit afficherCarteAutre(m_jeu->at(pJeuIndex+i)->getImage());
        }
        m_index += K_NBDISTCHIEN_5;
    } else {
        for (int i=0; i < K_NBDISTCHIEN_3_4; i++) {
            m_chien->append(m_jeu->at(pJeuIndex+i));
            emit afficherCarteAutre(m_jeu->at(pJeuIndex+i)->getImage());
        }
        m_index += K_NBDISTCHIEN_3_4;
    }
}

/*! \brief Fonction de test.

    Cette fonction permet d'afficher la liste des paramètres d'une carte.

    \param pC   Carte à afficher.
*/
void Partie::afficherCarte(Carte* pC) {
    QString tmp;
    switch (pC->getValeur()){
    case -1:
        switch (pC->getvaleurSpec()){
        case pc::Excuse:
            qDebug() << "Excuse";
            return;
            break;

        case pc::Valet:
            tmp = "Valet de ";
            break;

        case pc::Cavalier:
            tmp = "Cavalier de ";
            break;

        case pc::Dame:
            tmp = "Dame de ";
            break;

        case pc::Roi:
            tmp = "Roi de ";
            break;
        }
        break;

    default:
        tmp = QString::number(pC->getValeur());
        tmp += " de ";
        break;
    }

    switch (pC->getCouleur()){
    case pc::Coeur:
        tmp += "Coeur.";
        break;

    case pc::Carreaux:
        tmp += "Carreaux.";
        break;

    case pc::Trefle:
        tmp += "Trefle.";
        break;

    case pc::Pique:
        tmp += "Pique.";
        break;

    case pc::Atout:
        tmp += "Atout.";
        break;
    }

    qDebug() << tmp;
}
